"""
缓存管理模块
提供统一的缓存接口，支持Redis和内存缓存
提高响应速度，减少重复计算和API调用
"""

import json
import time
import logging
import asyncio
from typing import Any, Optional, Dict, Callable
from functools import wraps
from .config import settings

logger = logging.getLogger(__name__)

try:
    import redis.asyncio as redis
    REDIS_AVAILABLE = True
except ImportError:
    REDIS_AVAILABLE = False
    logger.warning("Redis不可用，将使用内存缓存")


class CacheManager:
    """
    统一缓存管理器
    自动选择Redis或内存缓存，提供一致的接口
    """
    
    def __init__(self):
        self.redis_client: Optional[redis.Redis] = None
        self.memory_cache: Dict[str, Dict] = {}
        self.is_redis_connected = False
        
    async def init_redis(self, redis_url: str = None):
        """
        初始化Redis连接
        
        Args:
            redis_url: Redis连接URL，默认使用配置中的URL
        """
        if not REDIS_AVAILABLE:
            logger.info("Redis不可用，使用内存缓存")
            return
            
        try:
            url = redis_url or settings.redis_url
            self.redis_client = redis.from_url(url, decode_responses=True)
            # 测试连接
            await self.redis_client.ping()
            self.is_redis_connected = True
            logger.info(f"Redis连接成功: {url}")
        except Exception as e:
            logger.warning(f"Redis连接失败，使用内存缓存: {e}")
            self.redis_client = None
            self.is_redis_connected = False
            
    async def get(self, key: str) -> Optional[Any]:
        """
        从缓存获取数据
        
        Args:
            key: 缓存键
            
        Returns:
            Any: 缓存的数据，如果不存在返回None
        """
        try:
            if self.is_redis_connected and self.redis_client:
                # 使用Redis缓存
                data = await self.redis_client.get(key)
                if data:
                    return json.loads(data)
            else:
                # 使用内存缓存
                cache_item = self.memory_cache.get(key)
                if cache_item:
                    # 检查是否过期
                    if time.time() < cache_item.get('expire_time', 0):
                        return cache_item['value']
                    else:
                        # 过期了，删除缓存项
                        del self.memory_cache[key]
            return None
        except Exception as e:
            logger.error(f"缓存获取失败 key={key}: {e}")
            return None
            
    async def set(self, key: str, value: Any, ttl: int = None):
        """
        设置缓存数据
        
        Args:
            key: 缓存键
            value: 要缓存的数据
            ttl: 生存时间（秒），默认使用配置中的TTL
        """
        ttl = ttl or settings.cache_ttl
        
        try:
            if self.is_redis_connected and self.redis_client:
                # 使用Redis缓存
                await self.redis_client.setex(key, ttl, json.dumps(value, ensure_ascii=False))
            else:
                # 使用内存缓存
                # 如果缓存过大，清理一些过期项
                if len(self.memory_cache) >= settings.max_cache_size:
                    await self._cleanup_memory_cache()
                
                self.memory_cache[key] = {
                    'value': value,
                    'expire_time': time.time() + ttl
                }
        except Exception as e:
            logger.error(f"缓存设置失败 key={key}: {e}")
    
    async def delete(self, key: str):
        """
        删除缓存项
        
        Args:
            key: 要删除的缓存键
        """
        try:
            if self.is_redis_connected and self.redis_client:
                await self.redis_client.delete(key)
            else:
                self.memory_cache.pop(key, None)
        except Exception as e:
            logger.error(f"缓存删除失败 key={key}: {e}")
    
    async def clear(self):
        """清空所有缓存"""
        try:
            if self.is_redis_connected and self.redis_client:
                await self.redis_client.flushdb()
            else:
                self.memory_cache.clear()
            logger.info("缓存已清空")
        except Exception as e:
            logger.error(f"缓存清空失败: {e}")
    
    async def _cleanup_memory_cache(self):
        """清理过期的内存缓存项"""
        current_time = time.time()
        expired_keys = [
            key for key, item in self.memory_cache.items()
            if current_time > item.get('expire_time', 0)
        ]
        
        for key in expired_keys:
            del self.memory_cache[key]
        
        # 如果清理后仍然过大，删除最旧的项
        while len(self.memory_cache) >= settings.max_cache_size:
            oldest_key = min(
                self.memory_cache.keys(),
                key=lambda k: self.memory_cache[k].get('expire_time', 0)
            )
            del self.memory_cache[oldest_key]
    
    def get_stats(self) -> Dict[str, Any]:
        """
        获取缓存统计信息
        
        Returns:
            Dict: 缓存统计信息
        """
        if self.is_redis_connected:
            return {
                "type": "redis",
                "connected": True,
                "memory_cache_size": 0
            }
        else:
            return {
                "type": "memory",
                "connected": False,
                "memory_cache_size": len(self.memory_cache),
                "max_cache_size": settings.max_cache_size
            }
    
    async def close(self):
        """
        关闭缓存连接
        清理资源
        """
        try:
            if self.redis_client:
                await self.redis_client.close()
                self.redis_client = None
                self.is_redis_connected = False
            
            # 清空内存缓存
            self.memory_cache.clear()
            logger.info("缓存管理器已关闭")
        except Exception as e:
            logger.error(f"关闭缓存管理器时出错: {e}")


# 全局缓存管理器实例
cache_manager = CacheManager()


def cache_response(key_prefix: str, ttl: int = None):
    """
    缓存装饰器
    自动缓存函数的返回结果，减少重复计算
    
    Args:
        key_prefix: 缓存键前缀
        ttl: 缓存生存时间（秒）
        
    Returns:
        Callable: 装饰后的函数
    """
    def decorator(func: Callable):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            # 生成缓存键（基于函数名和参数）
            cache_key = f"{key_prefix}:{hash(str(args) + str(kwargs))}"
            
            # 尝试从缓存获取
            cached_result = await cache_manager.get(cache_key)
            if cached_result is not None:
                logger.debug(f"缓存命中: {cache_key}")
                return cached_result
            
            # 执行原函数
            result = await func(*args, **kwargs)
            
            # 存入缓存（只缓存成功的结果）
            if result is not None:
                await cache_manager.set(cache_key, result, ttl)
                logger.debug(f"缓存更新: {cache_key}")
            
            return result
        return wrapper
    return decorator


# 初始化缓存
async def init_cache():
    """初始化缓存系统"""
    await cache_manager.init_redis() 